use std::marker::PhantomPinned;
use std::ops::Index;
use std::pin::Pin;
use std::ptr::NonNull;
use std::sync::Arc;
use crate::co;
use crate::decl::*;
use crate::gui::{*, events::*, privs::*};
use crate::prelude::*;
struct Obj { parent_ptr: NonNull<Base>,
radios: Vec<RadioButton>,
events: RadioGroupEvents,
_pin: PhantomPinned,
}
#[derive(Clone)]
pub struct RadioGroup(Pin<Arc<Obj>>);
unsafe impl Send for RadioGroup {}
impl Index<usize> for RadioGroup {
type Output = RadioButton;
fn index(&self, i: usize) -> &Self::Output {
&self.0.radios[i]
}
}
impl GuiNativeControlEvents<RadioGroupEvents> for RadioGroup {
fn on(&self) -> &RadioGroupEvents {
if *self.index(0).hwnd() != HWND::NULL {
panic!("Cannot add events after the control creation.");
} else if *unsafe { self.0.parent_ptr.as_ref() }.hwnd() != HWND::NULL {
panic!("Cannot add events after the parent window creation.");
}
&self.0.events
}
}
impl RadioGroup {
#[must_use]
pub fn new(
parent: &impl GuiParent,
opts: &[RadioButtonOpts],
) -> Self
{
if opts.is_empty() {
panic!("RadioGroup needs at least one RadioButton.");
}
let radios = opts.iter().enumerate()
.map(|(i, opt)| {
let mut radio_opt = opt.manual_clone();
if i == 0 { radio_opt.window_style |= co::WS::TABSTOP | co::WS::GROUP;
}
RadioButton::new(parent, radio_opt)
})
.collect::<Vec<_>>();
let ctrl_ids = radios.iter()
.map(|r| r.ctrl_id()) .collect::<Vec<_>>();
let opts_resz_s = opts.into_iter()
.map(|opt| OptsResz::Wnd(opt.clone()))
.collect::<Vec<_>>();
let new_self = Self(
Arc::pin(
Obj {
parent_ptr: NonNull::from(parent.as_ref()),
radios,
events: RadioGroupEvents::new(parent, ctrl_ids),
_pin: PhantomPinned,
},
),
);
let self2 = new_self.clone();
parent.as_ref().before_user_on().wm_create_or_initdialog(move |_, _| {
self2.create(&opts_resz_s)?;
Ok(WmRet::NotHandled)
});
new_self
}
#[must_use]
pub fn new_dlg(
parent: &impl GuiParent,
ctrls: &[(u16, Horz, Vert)],
) -> Self
{
if ctrls.is_empty() {
panic!("RadioGroup needs at least one RadioButton.");
}
let radios = ctrls.iter()
.map(|(ctrl_id, _, _)| RadioButton::new_dlg(parent, *ctrl_id))
.collect::<Vec<_>>();
let ctrl_ids = ctrls.iter()
.map(|(ctrl_id, _, _)| *ctrl_id)
.collect::<Vec<_>>();
let opts_resz_s = ctrls.iter()
.map(|(_, horz, vert)| OptsResz::Dlg((*horz, *vert)))
.collect::<Vec<_>>();
let new_self = Self(
Arc::pin(
Obj {
parent_ptr: NonNull::from(parent.as_ref()),
radios,
events: RadioGroupEvents::new(parent, ctrl_ids),
_pin: PhantomPinned,
},
),
);
let self2 = new_self.clone();
parent.as_ref().before_user_on().wm(co::WM::INITDIALOG, move |_, _| {
self2.create(&opts_resz_s)?;
Ok(WmRet::NotHandled)
});
new_self
}
fn create(&self,
opts_resz_s: &Vec<OptsResz<RadioButtonOpts>>,
) -> SysResult<()>
{
self.0.radios.iter()
.zip(opts_resz_s.iter())
.try_for_each(|(radio, opts_resz)|
radio.create(opts_resz) )
}
#[must_use]
pub fn iter(&self) -> std::slice::Iter<'_, RadioButton> {
self.0.radios.iter()
}
#[must_use]
pub fn checked(&self) -> Option<&RadioButton> {
self.checked_index().map(|idx| &self.0.radios[idx])
}
#[must_use]
pub fn checked_index(&self) -> Option<usize> {
self.0.radios.iter()
.position(|radio| radio.is_selected())
}
#[must_use]
pub fn count(&self) -> usize {
self.0.radios.len()
}
}